#include "pch.hpp"
#include "thread.hpp"

using namespace services;




thread::thread()
	: m_break(false)
	, m_exclusive(false)
{
	m_thread = boost::thread(boost::bind(&thread::run, this));
}
///////////////////////////////////////////////////////////////////////////////////////////////////

thread::thread(task::ptr t)
	: m_break(false)
	, m_exclusive(true)
{
	m_tasks.insert(t);

	m_thread = boost::thread(boost::bind(&thread::run, this));
}
///////////////////////////////////////////////////////////////////////////////////////////////////

thread::~thread()
{
	m_break = true;
	m_thread.join();
}
///////////////////////////////////////////////////////////////////////////////////////////////////




bool thread::joinable() const
{
	return m_thread.joinable();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

bool thread::exclusive() const
{
	return m_exclusive;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

std::size_t thread::numTasks() const
{
	return m_tasks.size();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void thread::add(task::ptr t)
{
	write_lock lock(m_mutex);
	m_tasks.insert(t);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

std::vector<task::const_ptr> thread::activeTasks()
{
	std::vector<task::const_ptr> _t;

	read_lock lock(m_mutex);
	std::for_each(m_tasks.begin(), m_tasks.end(), [&](task::ptr t)
	{
		_t.push_back(t);
	});

	return _t;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void thread::run()
{
	while(!m_break)
	{
		//
		// Execute all tasks
		//

		{
			write_lock lock(m_mutex);
			for(auto i = m_tasks.begin(); i != m_tasks.end();)
			{
				const task::ptr& t = *i;
				(*t)();

				// Tasks that are set to looped are repeated over and over
				// Only one-time-tasks are removed once they finished executing
				if(!t->looped())
					i = m_tasks.erase(i);
				else
					++i;
			}

			// A dedicated thread who's task is finished ends itself
			if(m_tasks.size() == 0 && m_exclusive == true)
				return;
		}

		boost::this_thread::sleep(boost::posix_time::millisec(1));
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
